/*
享元模式：运用共享技术有效地支持大量细粒度的对象。
享元模式（Flyweight Pattern）主要用于减少创建对象的数量，以减少内存占用和提高性能。
这种类型的设计模式属于结构型模式，它提供了减少对象数量从而改善应用所需的对象结构的方式。
在享元对象内部并且不会随环境改变而改变的共享部分，可以称为是享元对象的内部状态，而随环境改变而改变的、
不可以共享的状态就是外部状态了。
程杰. 大话设计模式

介绍
意图：运用共享技术有效地支持大量细粒度的对象。
主要解决：在有大量对象时，有可能会造成内存溢出，我们把其中共同的部分抽象出来，如果有相同的业务请求，
直接返回在内存中已有的对象，避免重新创建。
何时使用：
 1、系统中有大量对象。
 2、这些对象消耗大量内存。
 3、这些对象的状态大部分可以外部化。
 4、这些对象可以按照内蕴状态分为很多组，当把外蕴对象从对象中剔除出来时，每一组对象都可以用一个对象来代替。
 5、系统不依赖于这些对象身份，这些对象是不可分辨的。
如何解决：用唯一标识码判断，如果在内存中有，则返回这个唯一标识码所标识的对象。
关键代码：用 HashMap 存储这些对象。
应用实例：
1、JAVA 中的 String，如果有则返回，如果没有则创建一个字符串保存在字符串缓存池里面。
2、数据库的数据池。
优点：大大减少对象的创建，降低系统的内存，使效率提高。
缺点：提高了系统的复杂度，需要分离出外部状态和内部状态，而且外部状态具有固有化的性质，不应该随着内部状态的变化而变化，
否则会造成系统的混乱。
使用场景：
1、系统有大量相似对象。
2、需要缓冲池的场景。
注意事项：
1、注意划分外部状态和内部状态，否则可能会引起线程安全问题。
2、这些类必须有一个工厂对象加以控制。

享元模式，换句话说就是共享对象，在某些对象需要重复创建，且最终只需要得到单一结果的情况下使用。
以下例子中，内部状态为：网站分类key，外表状态为，用户User
*/
package main

import "fmt"

type User struct {
	name string
}

func (u *User) setName(name string) {
	u.name = name
}

func (u *User) getName() string {
	return u.name
}

type WebSite interface {
	Use(u *User)
}

type ConcreteWebSit struct {
	name string
}

func (c *ConcreteWebSit) setName(name string) {
	c.name = name
}

func (c *ConcreteWebSit) Use(u *User) {
	fmt.Println("网站分类：", c.name, " 用户：", u.getName())
}

type WebSiteFactory struct {
	flyweight map[string]WebSite
}

func (w *WebSiteFactory) initWebSiteFactory() {
	w.flyweight = make(map[string]WebSite)
}

func (w *WebSiteFactory) getWebSiteCategory(category string) WebSite {
	website, ok := w.flyweight[category]
	if ok {
		return website
	} else {
		w.flyweight[category] = &ConcreteWebSit{name: category}
		return w.flyweight[category]
	}
}

func (w *WebSiteFactory) getWebSiteCategoryCount() (i int) {
	for range w.flyweight {
		i++
	}
	return
}

func main() {
	f := new(WebSiteFactory)
	f.initWebSiteFactory()

	fx := f.getWebSiteCategory("产品展示")
	fx.Use(&User{name: "科科"})

	fy := f.getWebSiteCategory("产品展示")
	fy.Use(&User{name: "迈迈"})

	fz := f.getWebSiteCategory("视频网站")
	fz.Use(&User{name: "卢纶"})

	fw := f.getWebSiteCategory("个人博客")
	fw.Use(&User{name: "思思"})

	fh := f.getWebSiteCategory("个人博客")
	fh.Use(&User{name: "略略"})

	fmt.Println("网站分类总数为：", f.getWebSiteCategoryCount())
}
